﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Collections;

namespace WP7Contrib.View.Controls
{
  /// <summary>
  /// A lightweight list control that raises a Navigation event when items are clicked.
  /// </summary>
  /// <remarks>
  /// <para>A common pattern for presenting a list of items for the purposes of navigation is to use a
  /// ListBox control, where navigation occurs on SelectionChanged. However, a ListBox adds unnecessary elements
  /// to the visual tree to support selection, resulting in a longer page load time than is necessary.</para>
  /// <para>The <c>NavigationList</c> provides a more lightweight control for presenting lists for the
  /// purpose of navigation. A collection of items is bound to the <see cref="ItemsSource">ItemsSource</see> property
  /// with the <see cref="ItemTemplate">ItemTemplate</see> property indicating how each is rendered. When
  /// an item is clicked the <see cref="Navigation">Navigation</see> event is raised.</para>
  /// <para>see: <a href="http://www.scottlogic.co.uk/blog/colin/2011/04/a-fast-loading-windows-phone-7-navigationlist-control/">A Fast Loading Windows Phone 7 NavigationList Control</a></para>
  /// </remarks>
  public class NavigationList : ItemsControl
  {
    #region fields

    private bool _manipulationDeltaStarted;

    #endregion

    public NavigationList()
    {
      DefaultStyleKey = typeof(NavigationList);
    }
    

    protected override void PrepareContainerForItemOverride(DependencyObject depObj, object item)
    {
      base.PrepareContainerForItemOverride(depObj, item);

      var element = depObj as UIElement;

      // handle events on the elements added to the ItemsControl
      element.MouseLeftButtonUp += Element_MouseLeftButtonUp;
      element.ManipulationStarted += Element_ManipulationStarted;
      element.ManipulationDelta += Element_ManipulationDelta;
    }

    protected override void ClearContainerForItemOverride(DependencyObject depObj, object item)
    {
      base.ClearContainerForItemOverride(depObj, item);

      var element = depObj as UIElement;

      // remove event handlers
      element.MouseLeftButtonUp -= Element_MouseLeftButtonUp;
      element.ManipulationStarted -= Element_ManipulationStarted;
      element.ManipulationDelta -= Element_ManipulationDelta;
    }
        

    private void Element_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
      _manipulationDeltaStarted = true;
    }

    private void Element_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
    {
      _manipulationDeltaStarted = false;
    }

    private void Element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
      if (_manipulationDeltaStarted)
        return;

      // raises the Navigation event on mouse up, but only if a manipulation delta
      // has not started.            
      var element = sender as FrameworkElement;
      OnNavigation(new NavigationListEventArgs(element.DataContext));
    }

    /// <summary>
    /// Occurs when the user clicks on an item in the list
    /// </summary>
    public event EventHandler<NavigationListEventArgs> Navigation;
    
    /// <summary>
    /// Raises the Navigation event
    /// </summary>
    protected void OnNavigation(NavigationListEventArgs args)
    {
      if (Navigation != null)
      {
        Navigation(this, args);
      }
    }
  }

  /// <summary>
  /// Provides data for the Navigation event
  /// </summary>
  public class NavigationListEventArgs : EventArgs
  {
    internal NavigationListEventArgs(object item)
    {
      Item = item;
    }

    /// <summary>
    /// Gets the item that was navigated to
    /// </summary>
    public object Item { private set; get; }
  }
}
